home *** CD-ROM | disk | FTP | other *** search
/ PC World Interactive 7 / PC World Interactive 7.iso / program / cprog.EXE / C12.TXT < prev    next >
Text File  |  1996-07-05  |  12KB  |  274 lines

  1. DINAMIK YER ACMA
  2.  
  3. Dinamik yer acma, ilk karsilastiginizda korkutucu bir tanimdir, fakat
  4. aslinda o kadar zor degildir. Su ana kadar kullandigimiz tum degiskenler,
  5. statik degiskenler idiler. Yani, derleyici tarafindan, derleme yada link
  6. etabinda kendilerine yer ayrilmisti. (Aslinda bazilari "otomatik"
  7. degiskenler olduklarindan, derleyici tarafindan dinamik olarak yer
  8. ayrilmisti, fakat bu bize gorunmuyordu). Dinamik degiskenler, program
  9. yuklendiginde var olmayan, fakat gerektiginde kendilerine hafizada yer
  10. tahsis edilen degiskenlerdir. Bu metod ile, diledigimiz kadar degiskeni
  11. tanimlamak, kullanmak, ve baska degiskenlerin o sahayi kullanmasi icin,
  12. o sahayi tekrar serbest birakabiliriz. 
  13.  
  14. DINLIST.C:
  15. ================================================================
  16. main()
  17. {
  18. struct hayvan {
  19.    char ismi[25];
  20.    char cinsi[25];
  21.    int yasi;
  22. } *evcil1, *evcil2, *evcil3;
  23.  
  24.    evcil1 = (struct hayvan *)malloc(sizeof(struct hayvan));
  25.    strcpy(evcil1->ismi,"General");
  26.    strcpy(evcil1->cinsi,"Karisik Birsey");
  27.    evcil1->yasi = 1;
  28.  
  29.    evcil2 = evcil1;   /* evcil2 simdi yukaridaki veri
  30.                          yapisina karsilik geliyor */
  31.  
  32.    evcil1 = (struct hayvan *)malloc(sizeof(struct hayvan));
  33.    strcpy(evcil1->ismi,"Bobi");
  34.    strcpy(evcil1->cinsi,"Labrador");
  35.    evcil1->yasi = 3;
  36.  
  37.    evcil3 = (struct hayvan *)malloc(sizeof(struct hayvan));
  38.    strcpy(evcil3->ismi,"Kristal");
  39.    strcpy(evcil3->cinsi,"Alman Coban");
  40.    evcil3->yasi = 4;
  41.  
  42.        /* Yukardaki bilgiyi yazalim */
  43.  
  44.    printf("%s, bir %sdir ve %d yasindadir.\n", evcil1->ismi,
  45.            evcil1->cinsi, evcil1->yasi);
  46.  
  47.    printf("%s, bir %sdir ve %d yasindadir.\n", evcil2->ismi,
  48.            evcil2->cinsi, evcil2->yasi);
  49.  
  50.    printf("%s, bir %sdir ve %d yasindadir.\n", evcil3->ismi,
  51.            evcil3->cinsi, evcil3->yasi);
  52.  
  53.    evcil1 = evcil3;   /* evcil1 simdi evcil3 un gosterdigi
  54.                          yapiyi gosteriyor              */
  55.  
  56.    free(evcil3);    /* bir structure'u siliyor                 */
  57.    free(evcil2);    /* bu da bir baska structure'u siliyor     */
  58. /* free(evcil1);    bu yapilamaz - niye? anlatacagim!          */
  59. }
  60. ================================================================
  61.  
  62. "hayvan" isimli bir structure tanimlama ile basliyoruz. Bu tanimladigimiz
  63. tip ile bir degisken tanimlamiyoruz, sadece 3 tane pointer tanimliyoruz.
  64. Bu programin devamina da bakarsaniz, hicbir yerde bir degisken tanimina
  65. rastlayamazsiniz. Guzel. Veriyi saklayabilecegimiz hicbir yer yok.
  66. Elimizdeki yegane sey, 3 tane pointers dir. Birseyler yapabilmek icin,
  67. degiskenler tanimlamamiz gerekli, o zaman dinamik olarak tanimlayalim.
  68.  
  69. DINAMIK DEGISKEN TANIMLAMAK
  70.  
  71. Programin ilk satiri, "evcil1" isimli pointer'a birsey atayarak 3
  72. degiskenden olusan bir dinamik yapi tanimliyor. Programin kalbi, satirin
  73. ortasinda gomulu bulunan "malloc" fonksiyonudur. Bu, baska bilgilere
  74. ihtiyaci olan "hafiza ayir" fonksiyonudur. "malloc" fonksiyonu, normalde,
  75. hafizanin "heap" denilen kesiminde, "n" karakter boyunda, ve karakter
  76. tipinde bir yer ayiracaktir. "n", fonksiyona gecirilen yegane
  77. parametredir. "n" hakkinda birazdan konusacagiz, fakat ilk once "heap":
  78.  
  79. HEAP NEDIR?
  80.  
  81. Her derleyicinin calisacak kodun boyu, kac degisken
  82. kullanilabilecegi, kaynak kodun boyu gibi sinirlari vardir. IBM-PC ve
  83. uyumlular icin bu sinir cogu derleyici icin 64K lik bir calisacak kod
  84. boyudur. (Calisacak koddan kastim, ismi EXE yada COM ile biten
  85. kutuklerdir.) Bunun sebebi, IBM-PC nin 64K lik segman boyuna sahip bir
  86. mikroisleyiciye sahip olmasindandir. Daha "uzakta" yer alan veriye ise,
  87. ozel erisme yontemleri gerektirmektedir. Programi kucuk ve verimli tutmak
  88. icin, bu yontemler kullanilmamakta, ve program, cogu programlar icin
  89. yeterli olan 64K lik bir sahaya sigmak zorunlulugundadir.
  90.  
  91. Heap sahasi, bu 64K lik sahanin disinda bulunan ve programlarin veri ve
  92. degisken saklamak icin kullanilabilecekleri bir yerdir. Veriler ve
  93. degiskenler, sistem tarafindan "malloc" cagirilinca heap'e konur. Sistem,
  94. verinin nereye kondugunu takip eder. Istedigimizde, bir degiskeni tanimsiz
  95. yaparak, heap de bosluklar yaratiriz. Sistem bu bosluklara, yeni "malloc"
  96. tanimlari oldugunda baska veriler koyarak kullanir. Yani, heap'in yapisi
  97. son derece dinamiktir - surekli degisir..
  98.  
  99. SEGMANLAR HAKKINDA
  100.  
  101. Daha pahalli derleyiciler, kullanmak istediginiz hafiza tipini secmenizi
  102. saglarlar. Lattice yada Microsoft'un derleyicileri ile, program boyunun
  103. 64K nin altinda kalmasini, ve programin daha verimli calismasi ile
  104. programin 640K sinirinda kalmasi, daha uzun adresleme metodu ile daha az
  105. verimli calismasi arasinda bir secim yapabilirsiniz. Uzun adresleme,
  106. segmanlar arasi erisimi gerektireceginden, biraz daha yavas calisan
  107. programlara sebep olacaktir. Yavaslama, cogu programlar icin onemsiz
  108. olacaktir. 
  109.  
  110. Sayet bir programin kodu ve hafiza gereksinimi toplam 64K yi asmiyorsa, ve
  111. stack'i kullanmiyorsa, bir .COM kutugu haline getirilebilir. Bir .COM
  112. kutugu hafizanin bir kopyasi seklinde oldugu icin, cok hizli bir sekilde
  113. yuklenebilir. Halbuki .EXE tipindeki bir kutugun adreslerinin hafizada
  114. yeniden yerlestirilmesi gereklidir. Dolayisi ile ufak hafiza modeli, daha
  115. hizli yuklenen programlar yaratabilir. Bunun hakkinda endiselenmeyin,
  116. birkac programcinin endiselendigi ufak bir detaydir.
  117.  
  118. Dinamik tanimlama ile, verileri "heap" e saklamak mumkundur. Tabii, lokal
  119. degiskenleri, ve indeks sayaclari tipindeki degisenleri heap de saklamak
  120. istemezsiniz - sadece buyuk dizileri ve structure'lari..
  121.  
  122. Kucuk hafiza modelinde kalmaktan daha onemli birsey, bilgisayarin
  123. hafizasinin sinirlarinda kalmaktir. Sayet programiniz cok buyuk birkac
  124. saha tanimliyorsa, fakat bunlari ayni zamanda kullanmiyorsa, bir parcasini
  125. dinamik olarak tanimlayip, kullanip, silebilirsiniz. Sonra, ayni sahayi
  126. bir baska veri parcasi icin kullanabilirsiniz. 
  127.  
  128. "malloc" A GERI DONUS
  129.  
  130. Umarim, "heap" hakkindaki parca, size "malloc" ile ne yaptigimizi
  131. gostermistir. Sadece, sisteme kendisine bir parca hafiza verilmesini talep
  132. edip, bu sahanin ilk elemanina (baslangicina) bir pointer dondurmektedir.
  133. Parantezler arasinda gerekli olan yegane parametre, istenilen blok'un
  134. boyudur. Bu programda, basinda tanimladigimiz structure'u saklayabilecek
  135. bir yere ihtiyacimiz vardir. "sizeof", yeni bir fonksiyondur, en azindan
  136. bize, ve parantezlerinin icindeki parametresinin boyunu byte cinsinden
  137. dondurmektedir. Yani, "hayvan" structure'unun boyunu byte olarak
  138. dondurmektedir. Bu deger "malloc" a dondurulur. Fonksiyonu cagirinca bize
  139. heap'de bir saha ayrilmis oluyor, ve "evcil1" bu sahanin baslangicini
  140. gosteriyor. 
  141.  
  142. CAST NEDIR?
  143.  
  144. Hala, "malloc" fonksiyonun onunde, tuhaf gorunuslu bir birsey var. Buna
  145. "cast" denir. "malloc" fonksiyonu normalde, ayrilan sahanin baslangicini
  146. gosteren "char" tipli bir pointer dondurur. Cogu zaman, "char" tipli bir
  147. pointer istemeyiz. Biz bu ornekte, "hayvan" structure'unu gosterecek bir
  148. pointer istiyoruz, ve bu nedenle, derleyiciye bu tuhaf yapi ile bunu
  149. belirtiyoruz. Cast'i koymazsaniz, cogu derleyici, pointer'i dogru bir
  150. sekilde dondurecektir, size bir uyari mesaji verip, gayet iyi calisan bir
  151. program yaratacaktir. Iyi programlama teknigi, derleyicinin uyari
  152. mesajlari vermesine mani olmaktir. 
  153.  
  154.  
  155. DINAMIK OLARAK TANIMLADIGIMIZ SAHAYI KULLANMAK
  156.  
  157.  
  158. Structure ve pointer konusu ile ilgili konusmamizi hatirlarsaniz, sayet
  159. bir structure'umuz ve onu gosteren bir pointer'imiz varsa, icindeki
  160. herhangi bir degiskene erisebiliriz. Denemek icin, programin bundan
  161. sonraki 3 satirinda, structure'a degerler atayacagiz. Bu komutlarin statik
  162. olarak tanimli atamalara benzedigini fark edeceksiniz. 
  163.  
  164. Bundan sonraki satirda, "evcil1" in degerini "evcil2" ye atiyoruz. Bunu
  165. yapmak, yeni bir veri yaratmiyor, sadece ayni yeri gosteren iki tane
  166. pointer'imiz oluyor. "evcil2", simdi yarattigimiz structure'u gosterdigi
  167. icin, "evcil1", birbaska dinamik tanimli structure yaratmakta
  168. kullanilabilir. 
  169.  
  170.   o  "evcil2" yi de yeni dinamik tanim icin kullanabilirdik. 
  171.  
  172. Sonunda, bir baska saha tanimlayip, "evcil3" u bunun baslangicina
  173. atiyoruz. 
  174.  
  175. DINAMIK TANIMLI SAHADAN KURTULMAK
  176.  
  177. Birbaska yeni fonksiyon ise, "free" dir. Bu fonksiyon, ayirdigimiz hafiza
  178. parcasini tekrar sisteme iade etmekte kullanilir. Kullanimi icin, bloku
  179. gosteren bir pointer'i, parametre olarak gecirin.
  180.  
  181. Dinamik tanimin bir baska ozelligini gostermek icin, bir baska sey daha
  182. yapiyoruz. "evcil1" in degeri, "evcil3" e ataniyor. Bunu yaparak, "evcil1"
  183. in tuttugu degeri kaybetmis oluyoruz - cunku artik "evcil3" un degerini
  184. tutmaktadir. Dolayisi ile, artik hicbir zaman kullanilamaz. Bu hafiza
  185. sahasi, bu noktadan sonra erisilemez, ve "ziyan" olmustur. Bu, bir
  186. programda normal olarak yapmayacaginiz birseydir - sadece dikkatinizi
  187. cekmek icin konulmustur.
  188.  
  189. Ilk "free" fonksiyon cagirimi, "evcil1" ve "evcil3" un gosterdigi sahayi
  190. ortadan kaldirir, ikincisi de "evcil2" nin gosterdigi sahayi ortadan
  191. kaldirir. Dolayisi ile, daha once yarattigimiz verileri kaybetmis olduk.
  192. Heap'de bir parca daha bilgi vardir, fakat onun yerini gosteren bir
  193. pointer olmadigi icin, erisilemez. "evcil1" in sahasini tekrar "free"
  194. etmeye calismak, bir hata olacaktir, cunku zaten "evcil3" ile ayni yer
  195. ortadan kaldirilmistir. Fakat endiselenmeye luzum yoktur, cunku DOS a
  196. donunce, butun heap sahasi silinecektir.
  197.  
  198. BAYAGI COK KONUSTUK
  199.  
  200. Bu son program hakkinda nerdeyse 4 sayfa konustuk, fakat iyi harcanmis bir
  201. zaman idi bu. Sizin icin dinamik tanimlama hakkinda ogrenmediginiz hicbir
  202. seyin kalmadigini bilmek, sevindirici birsey olmali. Tabii ki, bu sahanin
  203. kullanimi hakkinda bircok sey orgenebilirsiniz, fakat dinamik tanimlama
  204. hakkinda daha fazla ogrenebileceginiz birsey yoktur.
  205.  
  206. BIR POINTER DIZISI
  207.  
  208. BUYUKDIN.C:
  209. ================================================================
  210.  
  211. main()
  212. {
  213. struct hayvan {
  214.    char ismi[25];
  215.    char cinsi[25];
  216.    int yasi;
  217. } *evcil[12], *point;       /* bu, 13 tane pointer ve
  218.                               0 degisken tanimliyor */
  219.     
  220. int index;
  221.  
  222.   /* ilk once, dinamik sahayi ivir zivirla dolduralim. */
  223.     
  224.    for (index = 0;index < 12;index++) {
  225.       evcil[index] = (struct hayvan *)malloc(sizeof(struct hayvan));
  226.       strcpy(evcil[index]->ismi,"General");
  227.       strcpy(evcil[index]->cinsi,"Karisik cins");
  228.       evcil[index]->yasi = 4;
  229.    }
  230.  
  231.    evcil[4]->yasi = 12;        /* Bu atamalar, bazi sahalara  */
  232.    evcil[5]->yasi = 15;        /*      nasil luzumsuz bilgi   */
  233.    evcil[6]->yasi = 10;        /*  yazilabilecegini gosterir. */
  234.  
  235.        /* yukarda tanimladiklarimizi yazalim.   */
  236.  
  237.    for (index = 0;index <12;index++) {
  238.       point = evcil[index];
  239.       printf("%s, bir %s, ve %d yasindadir.\n", point->ismi,
  240.               point->cinsi, point->yasi);
  241.    }
  242.  
  243.    /* Iyi programlama teknigi, dinamik yaratilmis sahanin, */
  244.    /* sisteme iade edilmesini soyler..                     */
  245.  
  246.    for (index = 0;index < 12;index++)
  247.       free(evcil[index]);
  248. }
  249.  
  250. ================================================================
  251.  
  252. Bu program, bir oncekine cok benzer. Basit tutmak icin, 12 elemanlik bir
  253. pointer dizisi tanimliyoruz, ve bir "point" isimli bir pointer daha
  254. tanimliyoruz. 
  255.  
  256. Size yeni olan "*evcil[12]" terimini biraz anlatmakta fayda var. Burada
  257. yaptigimiz 12 tane pointer'dan olusan bir dizi tanimladik. Ilki "evcil[0]"
  258. ve sonuncusu "evcil[11]". Aslinda, bir diziyi indekssiz kullanmak, o
  259. dizinin adresini verdiginden, kendi basina "evcil" demekle, pointerin
  260. pointerini tanimlamis oluyoruz. Bu C de tumuyle yasaldir, ve hatta daha
  261. ileri de gidebilirsiniz - fakat cabucak kafaniz karisir. Dolayisi ile,
  262. "int ****pt" demek, yasaldir, ve bu bir pointer'in pointer'inin
  263. pointer'inin pointer'ini tanimlar - sayet dogru saydiysam. Iyice C ye
  264. alisincaya kadar bu tip seylerden kacinmanizi tavsiye ederim.
  265.  
  266. Simdi, 12 tane pointer'imiz var, ve biz bunlar herhangi bir pointer gibi
  267. kullanabiliriz. Bir dongu icinde kendimize dinamik yer acip, icine
  268. istedigimiz verileri yazabiliriz. Rastgele secilmis bazi sahalara yeniden
  269. bilgi atadiktan sonra, ekrana sonuclari yaziyoruz. "point" isimli pointer,
  270. sadece size gosterme amaci ile kullanilmistir. Veri, "evcil[n]" diyerek
  271. tanimlanabilirdi. Son olarak 12 veri bloku "free" ile serbest birakilir ve
  272. program sona erer.
  273.  
  274.